# -*- coding: UTF-8 -*-
"""
@auth:buxiangjie
@date:2022/2/16 19:56
@describe: 断言封装
"""
import json
import re
import allure
import pytest

from assertpy.assertpy import assert_that, soft_assertions
from common.config_content import BoxContent
from typing import Iterable
from common.common_func import Common
from common.db_operate.db_operate import AssertData
from jsonpath import jsonpath


@allure.step("加载断言")
class UnitAssert:
	"""
	断言封装
	"""

	def __init__(self, param: dict, rep: dict, drop_down_content: dict):
		self.param = param
		self.rep = rep
		self.drop_down_content = drop_down_content

	def exec_func(self, env: str, func: str) -> None:
		"""
		动态调用类函数
		:param env: 环境
		:param func: 函数名称与参数
		:return:
		"""
		n_func = func.split("@")[1]
		kwg = {
			"env": env
		}
		func_name = n_func.split("(")[0]
		re_func = re.search(r'[(](.*?)[)]', n_func).group()
		if len(re_func) > 2:
			n_re_func = re_func.strip("(").strip(")").split(",")
			for n in n_re_func:
				if "|" in n:
					kwg[n.split("=")[0]] = (n.split("=")[1]).split("|")
				else:
					kwg[n.split("=")[0]] = n.split("=")[1]
		getattr(self, func_name)(**kwg)

	def _basic_assert(self, code: Iterable = (2000,)):
		"""基础断言"""
		assert_that(self.rep["resultCode"], "断言resultCode是否正确").is_in(*code)

	@allure.step("断言产品信息查询")
	def assert_config_product_dict(self, **kwargs) -> None:
		"""断言产品信息查询"""
		self._basic_assert()

		if kwargs.get("is_hidden", None):
			with soft_assertions():
				for group in self.rep["content"]:
					if group["value"] in kwargs["is_hidden"]:
						assert_that(group["isHidden"], f"断言产品组{group['desc']}是否隐藏").is_equal_to(1)
					else:
						assert_that(group["isHidden"], f"断言产品组{group['desc']}是否隐藏").is_equal_to(0)

		if self.param["scenarios"] in (0, 1, 4):
			assert_that(len(self.rep["content"]), "断言响应内容长度是否大于等于1").is_greater_than_or_equal_to(1)

	@allure.step("断言通用选项内容查询")
	def assert_config_drop_down_box_content(self, **kwargs) -> None:
		"""断言通用选项内容查询"""
		self._basic_assert()
		assert_that(len(self.rep["content"]), "断言响应内容长度是否大于等于1").is_greater_than_or_equal_to(1)

	@allure.step("断言授信列表")
	def assert_credit_list(self, **kwargs) -> None:
		"""断言授信列表"""
		self._basic_assert()
		with soft_assertions():
			assert_that(len(self.rep["content"]["records"]), "断言响应结果中records和size长度是否一致").is_less_than_or_equal_to(self.rep["content"]["size"])
			assert_that(self.rep["content"]["size"], "断言响应结果中size与请求参数是否一致").is_equal_to(self.param.get("size", ""))
			assert_that(self.rep["content"]["current"], "断言响应结果中当前页与请求参数是否一致").is_equal_to(self.param["current"])
			for record in self.rep["content"]["records"]:
				assert_that(record.get("productName", ""), "断言响应结果中产品名称不为空").is_not_empty()
				if self.param.get("creditId", ""):
					assert_that(record.get("creditId", "断言响应结果中授信ID与请求参数是否一致")).is_equal_to(str(self.param["creditId"]))
				if self.param.get("userId", ""):
					assert_that(record.get("userId", ""), "断言响应结果中用户ID与请求参数是否一致").is_equal_to(str(self.param["userId"]))
				if self.param.get("sourceUserId", ""):
					assert_that(record.get("sourceUserId", ""), "断言响应结果中来源用户ID与请求参数是否一致").is_equal_to(self.param["sourceUserId"])
				if self.param.get("productGroupIdList", []):
					assert_that(record.get("productId", "")).is_in(*self.param["productGroupIdList"])
				if self.param.get("creditStatus", "") != "ALL":
					assert_that(
						val=jsonpath(self.drop_down_content["creditResult"], f"$..?(@.desc=='{record['creditResult']}').value")[0],
						description="断言响应结果中授信结果creditResult与请求参数creditStatus是否一致"
					).is_equal_to(self.param["creditStatus"])
				if self.param.get("startDate", ""):
					# 断言响应结果中的授信时间是否在请求区间内
					condition = (
						self.param.get("creditId", ""),
						self.param.get("userId", ""),
						self.param.get("sourceUserId", "")
					)
					if any(condition):
						pass
					else:
						assert_that(Common.date_interval(self.param["startDate"], self.param["endDate"], record.get("creditApplyTime"))).is_true()

	@allure.step("断言授信统计")
	def assert_credit_total(self, **kwargs) -> None:
		"""断言授信统计"""
		self._basic_assert()
		with soft_assertions():
			if self.rep["content"]["creditTotalNumber"] > 0:
				assert_that(float(self.rep["content"]["creditTotalAmount"])).is_greater_than(0)
			if float(self.rep["content"]["creditTotalAmount"]) > 0:
				assert_that(self.rep["content"]["creditTotalNumber"]).is_greater_than(0)

	@allure.step("断言授信详情")
	def assert_credit_info(self, **kwargs) -> None:
		"""断言授信详情"""
		self._basic_assert()
		if self.rep["content"]["creditBaseBusinessInfo"]["productGroupId"] not in BoxContent.CREDIT_COMPANY.value:
			assert_that(self.rep["content"].get("creditCustomerForPersonalInfo", "断言个人用户授信信息")).is_not_empty()
		else:
			assert_that(self.rep["content"].get("creditCustomerForCompanyInfo", "断言企业用户授信信息")).is_not_empty()

	@allure.step("断言合同确认操作")
	def assert_confirm_contract(self, **kwargs) -> None:
		"""断言合同确认操作"""
		if kwargs.get("case", "") == "current_all":
			self._basic_assert((2002, 2000))

	@allure.step("断言放款确认操作")
	def assert_loan_confirm(self, **kwargs) -> None:
		"""断言放款确认操作"""
		self._basic_assert((2002, 2000))

	@allure.step("断言文件下载操作")
	def assert_file_download(self, **kwargs) -> None:
		"""断言文件下载操作"""
		try:
			rep = json.loads(json.dumps(self.rep))
			if rep["resultCode"] != 2000:
				pytest.fail("文件下载异常")
		except Exception:
			pass

	@allure.step("断言进件列表操作")
	def assert_project_list(self, **kwargs) -> None:
		"""断言进件列表操作"""
		self._basic_assert()
		with soft_assertions():
			assert_that(
				val=len(self.rep["content"]["records"]),
				description="断言响应结果中records和size长度是否一致"
			).is_less_than_or_equal_to(self.rep["content"]["size"])
			assert_that(
				val=self.rep["content"]["size"],
				description="断言响应结果中size与请求参数是否一致"
			).is_equal_to(self.param.get("size", ""))
			assert_that(
				val=self.rep["content"]["current"],
				description="断言响应结果中当前页与请求参数是否一致"
			).is_equal_to(self.param["current"])
			for record in self.rep["content"]["records"]:
				if self.param.get("projectId", ""):
					assert_that(
						val=record.get("projectId", ""),
						description="断言响应结果中进件ID与请求参数是否一致"
					).is_equal_to(str(self.param["projectId"]))
				if self.param.get("sourceProjectId", ""):
					assert_that(
						val=record.get("sourceProjectId", ""),
						description="断言响应结果中来源进件ID与请求参数是否一致"
					).is_equal_to(str(self.param["sourceProjectId"]))
				if self.param.get("sourceUserId", ""):
					assert_that(
						val=record.get("sourceUserId", ""),
						description="断言响应结果中来源用户ID与请求参数是否一致"
					).is_equal_to(str(self.param["sourceUserId"]))
				if self.param.get("auditResultStatus", "") != "ALL":
					assert_that(
						val=jsonpath(self.drop_down_content["projectAuditResult"], f"$..?(@.desc=='{record['auditResultDesc']}').value")[0],
						description="断言响应结果中授信结果auditResultDesc与请求参数auditResultStatus是否一致"
					).is_in(*self.param["auditResultStatus"])
				if self.param.get("userId", ""):
					assert_that(
						val=record.get("userId", ""),
						description="断言响应结果中用户ID与请求参数是否一致"
					).is_equal_to(str(self.param["userId"]))
				if self.param.get("idCardNum", ""):
					kwargs["project_id"] = record.get("projectId", "")
					assert_that(
						val=AssertData().get_id_card(**kwargs),
						description="断言响应结果中进件信息是否与请求身份证号一致"
					).is_equal_to(str(self.param["idCardNum"]))
				if self.param.get("startDate", ""):
					# 断言响应结果中的授信时间是否在请求区间内
					condition = (
						self.param.get("projectId", ""),
						self.param.get("sourceProjectId", ""),
						self.param.get("sourceUserId", ""),
						self.param.get("userId", ""),
						self.param.get("idCardNum", "")
					)
					if any(condition):
						pass
					else:
						assert_that(Common.date_interval(self.param["startDate"], self.param["endDate"], record.get("projectApplyTime"))).is_true()

	@allure.step("断言分润统计操作")
	def assert_profit_statistic_summary(self, **kwargs):
		self._basic_assert()
		for record in self.rep["content"]["records"]:
			assert_that(record["checkCode"], "校验响应结果中的分润场景是否在筛选条件中").is_in(*self.param["virgoCheckCodeList"])

	@allure.step("断言分润明细操作")
	def assert_profit_list(self, **kwargs):
		self._basic_assert()
		with soft_assertions():
			for record in self.rep["content"]["records"]:
				if self.param["ownerChannel"]:
					assert_that(
						val=record["ownerChannelDesc"],
						description="断言响应结果中ownerChannelDesc是否与筛选条件ownerChannel一致"
					).is_equal_to(jsonpath(self.drop_down_content["allChannelId"], f"$..?(@.value=='{self.param['ownerChannel']}').desc")[0])
				if self.param["productGroupList"]:
					assert_that(
						val=jsonpath(self.drop_down_content["allProductGroupId"], f"$..?(@.desc=='{record['productName']}').value")[0],
						description="断言响应结果中productName是否与筛选条件productGroupList一致"
					).is_in(*self.param["productGroupList"])
				if self.param["repayTypeList"]:
					assert_that(
						val=jsonpath(self.drop_down_content["profitRepayType"], f"$..?(@.desc=='{record['repayTypeDesc']}').value")[0],
						description="断言响应结果中repayTypeDesc是否与筛选条件repayTypeList一致"
					).is_in(*self.param["repayTypeList"])
				if self.param["subjectTypeList"]:
					assert_that(
						val=jsonpath(self.drop_down_content["profitSubjectType"], f"$..?(@.desc=='{record['subjectTypeDesc']}').value")[0],
						description="断言响应结果中subjectTypeDesc是否与筛选条件subjectTypeList一致"
					).is_in(*self.param["subjectTypeList"])
				if self.param["detailSubjectTypeList"]:
					assert_that(
						val=jsonpath(self.drop_down_content["profitDetailSubjectType"], f"$..?(@.desc=='{record['detailSubjectTypeDesc']}').value")[0],
						description="断言响应结果中detailSubjectTypeDesc是否与筛选条件detailSubjectTypeList一致"
					).is_in(*self.param["detailSubjectTypeList"])

	@allure.step("断言资产列表操作")
	def assert_asset_list(self, **kwargs):
		self._basic_assert()
		with soft_assertions():
			for record in self.rep["content"]["records"]:
				if self.param["startDate"]:
					# 断言响应结果中的时间是否在请求区间内
					condition = (
						self.param.get("assetId", ""),
						self.param.get("projectId", ""),
						self.param.get("sourceProjectId", ""),
						self.param.get("transactionId", ""),
						self.param.get("userId", ""),
						self.param.get("sourceUserId", "")
					)
					if any(condition):
						pass
					else:
						assert_that(Common.date_interval(self.param["startDate"], self.param["endDate"], assert_time=record["loanTime"])).is_true()
				if self.param["assetId"]:
					assert_that(record["assetId"], "断言响应结果中assetId是否与筛选条件assetId一致").is_equal_to(self.param["assetId"])
				if self.param["projectId"]:
					assert_that(record["projectId"], "断言响应结果中projectId是否与筛选条件projectId一致").is_equal_to(self.param["projectId"])
				if self.param["sourceProjectId"]:
					assert_that(record["sourceProjectId"], "断言响应结果中sourceProjectId是否与筛选条件sourceProjectId一致").is_equal_to(self.param["sourceProjectId"])
				if self.param["transactionId"]:
					assert_that(record["transactionId"], "断言响应结果中transactionId是否与筛选条件transactionId一致").is_equal_to(self.param["transactionId"])
				if self.param["userId"]:
					assert_that(str(record["userId"]), "断言响应结果中userId是否与筛选条件userId一致").is_equal_to(str(self.param["userId"]))
				if self.param["sourceUserId"]:
					assert_that(record["sourceUserId"], "断言响应结果中sourceUserId是否与筛选条件sourceUserId一致").is_equal_to(self.param["sourceUserId"])
				if self.param["loanTermFrom"]:
					assert_that(record["maturity"], "断言响应结果中的maturity是否大于等于筛选条件loanTermFrom").is_greater_than_or_equal_to(int(self.param["loanTermFrom"]))
				if self.param["loanTermTo"]:
					assert_that(record["maturity"], "断言响应结果中的maturity是否小于等于筛选条件loanTermFrom").is_less_than_or_equal_to(int(self.param["loanTermFrom"]))
				if self.param["overdueDaysFrom"]:
					assert_that(record["curOverdueDays"], "断言响应结果curOverdueDays是否大于等于筛选条件overdueDaysFrom").is_greater_than_or_equal_to(int(self.param["overdueDaysFrom"]))
				if self.param["overdueDaysTo"]:
					assert_that(record["curOverdueDays"], "断言响应结果curOverdueDays是否小于等于筛选条件overdueDaysTo").is_less_than_or_equal_to(int(self.param["overdueDaysTo"]))
				if self.param["productGroupIdList"]:
					assert_that(str(record["productGroupId"]), "断言响应结果中productGroupId是否与筛选条件productGroupIdList一致").is_in(*self.param["productGroupIdList"])
				if self.param["currentChannelList"]:
					kwargs["project_id"] = record["projectId"]
					assert_that(str(AssertData().get_current_channel(**kwargs)), "断言响应结果中currentChannel是否与筛选条件currentChannelList一致").is_in(*self.param["currentChannelList"])
				if self.param["assetStatusList"]:
					kwargs["project_id"] = record["projectId"]
					assert_that(str(AssertData().get_asset_status(**kwargs)), "断言响应结果中assetStatus是否与筛选条件assetStatusList一致").is_in(*self.param["assetStatusList"])

	@allure.step("断言还款汇总列表操作")
	def assert_query_repayment_total_list(self, **kwargs):
		"""断言还款汇总列表操作"""
		self._basic_assert()
		if self.rep["content"]:
			for record in self.rep["content"]:
				if self.param["overdueStatus"] and self.param["overdueStatus"] != "ALL":
					assert_that(str(record["overdueStatus"]), "断言响应结果中overdueStatus是否与筛选条件overdueStatus一致").is_equal_to(self.param["overdueStatus"])
				if self.param["productGroupIdList"]:
					assert_that(str(record["productGroupId"]), "断言响应结果中productGroupId是否与筛选条件productGroupIdList一致").is_in(*self.param["productGroupIdList"])
				if self.param["ownerChannelList"]:
					assert_that(str(record["ownerChannel"]), "断言响应结果中ownerChannel是否与筛选条件ownerChannelList一致").is_in(*self.param["ownerChannelList"])
				if self.param["repayTypeList"]:
					assert_that(str(record["repayType"]), "断言响应结果中repayType是否与筛选条件repayTypeList一致").is_in(*self.param["repayTypeList"])
				if self.param["creditMethodTypeList"]:
					assert_that(str(record["creditAssignMethod"]), "断言响应结果中creditAssignMethod是否与筛选条件creditMethodTypeList一致").is_in(*self.param["creditMethodTypeList"])
				if self.param["repaymentPlanTypeList"]:
					assert_that(str(record["planType"]), "断言响应结果中planType是否与筛选条件repaymentPlanTypeList一致").is_in(*self.param["repaymentPlanTypeList"])

	@allure.step("断言债转汇总列表操作")
	def assert_query_asset_swap_detail_total_list(self, **kwargs):
		"""断言债转汇总列表操作"""
		self._basic_assert()
		if self.rep["content"]:
			for record in self.rep["content"]:
				if self.param["productGroupIdList"]:
					assert_that(
						val=jsonpath(self.drop_down_content["allProductGroupId"], f"$..?(@.desc=='{record['productGroupName']}').value")[0],
						description="断言响应结果中productGroupName是否与筛选条件productGroupList一致"
					).is_in(*self.param["productGroupIdList"])
				if self.param["currentChannelList"]:
					assert_that(record["currentChannel"], "断言响应结果中currentChannel是否与筛选条件currentChannelList一致").is_in(*self.param["currentChannelList"])
				if self.param["creditAssignMethodList"]:
					assert_that(str(record["creditAssignMethod"]), "断言响应结果中creditAssignMethod是否与筛选条件creditAssignMethodList一致").is_in(*self.param["creditAssignMethodList"])
				if self.param["repaymentPlanTypeList"]:
					assert_that(str(record["category"]), "断言响应结果中category是否与筛选条件repaymentPlanTypeList一致").is_in(*self.param["repaymentPlanTypeList"])

	@allure.step("断言用户额度操作")
	def assert_user_amount_list(self, **kwargs):
		"""断言用户额度操作"""
		self._basic_assert()
		for record in self.rep["content"]["records"]:
			if self.param["startExpireDate"]:
				# 断言响应结果中的授信时间是否在请求区间内
				condition = (
					self.param.get("amountId", ""),
					self.param.get("userId", ""),
					self.param.get("sourceUserId", "")
				)
				if any(condition):
					pass
				else:
					assert_that(Common.date_interval(self.param["startExpireDate"], self.param["endExpireDate"], record["expireDate"]), "断言过期时间是否在筛选条件内").is_true()
			if self.param["amountId"]:
				assert_that(int(record["amountId"]), "断言响应结果中amountId是否与筛选条件amountId一致").is_equal_to(self.param["amountId"])
			if self.param["userId"]:
				assert_that(int(record["userId"]), "断言响应结果中userId是否与筛选条件userId一致").is_equal_to(self.param["userId"])
			if self.param["sourceUserId"]:
				assert_that(record["sourceUserId"], "断言响应结果中sourceUserId是否与筛选条件sourceUserId一致").is_equal_to(self.param["sourceUserId"])
			if self.param["expire"] and self.param["expire"] != "ALL":
				assert_that(str(record["expire"]), "断言响应结果中expire是否与筛选条件expire一致").is_equal_to(self.param["expire"])
			if self.param["productGroupIdList"]:
				assert_that(str(record["productGroupId"]), "断言响应结果中productGroupId是否与筛选条件productGroupIdList一致").is_in(*self.param["productGroupIdList"])

	@allure.step("断言用户额度详情操作")
	def assert_user_amount_detail_list(self, **kwargs):
		"""断言用户额度详情操作"""
		self._basic_assert()
		for record in self.rep["content"]["records"]:
			if self.param["amountId"]:
				assert_that(int(record["amountId"]), "断言响应结果中amountId是否与筛选条件amountId一致").is_equal_to(self.param["amountId"])
			if self.param["id"]:
				assert_that(record["id"], "断言响应结果中id是否与筛选条件id一致").is_equal_to(self.param["id"])
			if self.param["occurrence"]:
				assert_that(record["occurrence"], "断言响应结果中occurrence是否与筛选条件occurrence一致").is_equal_to(self.param["occurrence"])

	@allure.step("断言债转合同确认操作")
	def assert_confirm_contract_list(self, **kwargs):
		"""断言债转合同确认操作"""
		self._basic_assert()
		for record in self.rep["content"]["items"]["records"]:
			if self.param["startDate"]:
				assert_that(Common.date_interval(self.param["startDate"], self.param["endDate"], record["businessDate"]), "断言过期时间是否在筛选条件内").is_true()
			if self.param["confirmStatus"] and self.param["confirmStatus"] != "ALL":
				assert_that(str(record["confirmStatus"]["value"]), "断言响应结果中confirmStatus-value是否与筛选条件confirmStatus一致").is_in(*self.param["confirmStatus"])
			if self.param["productGroupIds"]:
				assert_that(str(record["productGroupId"]), "断言响应结果中productGroupId是否与筛选条件productGroupIds一致").is_in(*self.param["productGroupIds"])
			if self.param["businessEventTypes"]:
				assert_that(str(record["businessEventType"]["value"]), "断言响应结果中businessEventType-value是否与筛选条件businessEventTypes一致").is_in(*self.param["businessEventTypes"])

	@allure.step("断言债转合同确认详情操作")
	def assert_confirm_contract_list_record(self, **kwargs):
		"""断言债转合同确认详情操作"""
		self._basic_assert()
		for record in self.rep["content"]["items"]["records"]:
			if self.param["assetId"]:
				assert_that(int(record["assetId"]), "断言响应结果中assetId是否与筛选条件assetId一致").is_equal_to(self.param["assetId"])
			if self.param["sourceProjectId"]:
				assert_that(record["sourceProjectId"], "断言响应结果中sourceProjectId是否与筛选条件sourceProjectId一致").is_equal_to(self.param["sourceProjectId"])
			if self.param["confirmResult"] and self.param["confirmResult"] != "ALL":
				assert_that(
					val=int(jsonpath(self.drop_down_content["confirmResult"], f"$..?(@.desc=='{record['confirmResult']['value']}').value")[0]),
					description="断言响应结果中confirmResult-value是否与筛选条件confirmResult一致"
				).is_equal_to(int(self.param["confirmResult"]))

	@allure.step("断言资金流水列表操作")
	def assert_cash_query(self, **kwargs):
		"""断言资金流水列表操作"""
		self._basic_assert()
		for record in self.rep["content"]["records"]:
			if self.param["finishTimeStart"]:
				# 断言响应结果中的还款时间是否在请求区间内
				condition = (
					self.param.get("projectId", ""),
					self.param.get("serviceSn", "")
				)
				if any(condition):
					pass
				else:
					assert_that(Common.date_interval(self.param["finishTimeStart"], self.param["finishTimeEnd"], record["finishTime"]), "断言还款时间").is_true()
			if self.param["projectId"]:
				assert_that(str(record["projectId"]), "断言响应结果中projectId是否与筛选条件projectId一致").is_equal_to(self.param["projectId"])
			if self.param["serviceSn"]:
				assert_that(str(record["serviceSn"]), "断言响应结果中serviceSn是否与筛选条件serviceSn一致").is_equal_to(self.param["serviceSn"])
			if self.param["productGroupIdList"]:
				assert_that(str(record["productGroupId"]), "断言响应结果中productGroupId是否与筛选条件productGroupIdList一致").is_equal_to(*self.param["productGroupIdList"])
			if self.param["fundingSourceList"]:
				assert_that(
					val=str(jsonpath(self.drop_down_content["fundingSource"], f"$..?(@.desc=='{record['fundingSource']}').value")[0]),
					description="断言响应结果中fundingSource是否与筛选条件fundingSource一致"
				).is_in(*self.param["fundingSourceList"])

	@allure.step("断言日志列表操作")
	def assert_log_list(self, **kwargs):
		"""断言日志列表操作"""
		self._basic_assert()
		for record in self.rep["content"]["records"]:
			if self.param["startTime"]:
				assert_that(Common.date_interval(self.param["startTime"], self.param["endTime"], record["createTime"]), "断言日志日期").is_true()
			if self.param["username"]:
				assert_that(record["username"], "断言响应结果中username是否与筛选条件username一致").is_equal_to(self.param["username"])
			if self.param["logLevel"] and self.param["logLevel"] != "ALL":
				assert_that(
					val=int(jsonpath(self.drop_down_content["logLevel"], f"$..?(@.desc=='{record['logLevelDesc']}').value")[0]),
					description="断言响应结果中logLevelDesc是否与筛选条件logLevel一致"
				).is_equal_to(int(self.param["logLevel"]))
			if self.param["logTypeList"]:
				assert_that(
					val=str(jsonpath(self.drop_down_content["logType"], f"$..?(@.desc=='{record['logTypeDesc']}').value")[0]),
					description="断言响应结果中logTypeDesc是否与筛选条件logTypeList一致"
				).is_in(*self.param["logTypeList"])
